# -*- coding: utf-8 -*-
# cython: language_level=3
import pymysql
from threading import Lock

from config import MYSQL_DB, MYSQL_IP, MYSQL_PASSWD, MYSQL_PORT, MYSQL_USER
from utils.log import log

mysql_lock = Lock()


class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_inst'):
            cls._inst = super(Singleton, cls).__new__(cls, *args, **kwargs)

        return cls._inst


class MysqlDB(Singleton):
    def __init__(self, ip=MYSQL_IP, port=MYSQL_PORT, db=MYSQL_DB, user_name=MYSQL_USER, user_pass=MYSQL_PASSWD):
        try:
            self.conn = pymysql.connect(host=ip, port=port, user=user_name, passwd=user_pass, db=db,
                                        charset='utf8mb4')
        except Exception as e:
            log.error(e)
            raise e

    def mogrify(self, sql="", args=None):
        self.conn.ping()
        with mysql_lock:
            try:
                with self.conn.cursor() as cursor:
                    try:
                        if isinstance(args, list):
                            result = [cursor.mogrify(sql, args=i) for i in args]
                        else:
                            result = cursor.mogrify(sql, args=args)
                    except Exception as e:
                        try:
                            log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                        except:
                            log.error(f"{(e, sql, args)}")
                    else:
                        return result
            except:
                pass

    def find(self, sql, fetch_one=False, to_json=False, args=None):
        self.conn.ping()
        with mysql_lock:
            try:
                with self.conn.cursor() as cursor:
                    count = cursor.execute(sql, args=args)
                    if fetch_one:
                        result = cursor.fetchone()
                    else:
                        result = cursor.fetchall()

                    if to_json and result:
                        key_name = list(i[0] for i in cursor.description)
                        if fetch_one:
                            result = dict(zip(key_name, result))
                        else:
                            result = [dict(zip(key_name, i)) for i in result]

                    return result
            except Exception as e:
                try:
                    log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                except:
                    log.error(f"{(e, sql, args)}")

    def add(self, sql, args=None, exception_callfunc=''):
        self.conn.ping()
        with mysql_lock:

            try:
                with self.conn.cursor() as cursor:
                    try:
                        if isinstance(args, list):
                            cursor.executemany(sql, args=args)
                        else:
                            cursor.execute(sql, args=args)
                        mid = self.conn.insert_id()
                        self.conn.commit()
                    except Exception as e:
                        self.conn.rollback()
                        if e.args[0] != 1062:
                            try:
                                log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                            except:
                                log.error(f"{(e, sql, args)}")
                        # if exception_callfunc:
                        #     exception_callfunc(e)
                        return False
                    else:
                        return mid
            except:
                pass

    def update(self, sql, args=None):
        self.conn.ping()
        with mysql_lock:

            try:
                with self.conn.cursor() as cursor:
                    try:
                        cursor.execute(sql, args=args)
                        row_count = cursor.rowcount
                        self.conn.commit()
                    except Exception as e:
                        try:
                            log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                        except:
                            log.error(f"{(e, sql, args)}")
                        self.conn.rollback()

                        return False
                    else:
                        return row_count
            except:
                pass

    def delete(self, sql, args=None):
        self.conn.ping()
        with mysql_lock:

            try:
                with self.conn.cursor() as cursor:
                    try:
                        cursor.execute(sql, args=args)
                        self.conn.commit()
                    except Exception as e:
                        try:
                            log.error(f"{(e, cursor.mogrify(sql, args=args))}")
                        except:
                            log.error(f"{(e, sql, args)}")
                        self.conn.rollback()
                        return False
                    else:
                        return True
            except:
                pass

    def set_unique_key(self, table, key):
        self.conn.ping()
        with mysql_lock:

            try:
                with self.conn.cursor() as cursor:
                    try:
                        sql = 'alter table %s add unique (%s)' % (table, key)
                        cursor.execute(sql)
                        self.conn.commit()

                    except Exception as e:
                        log.error(table + ' ' + str(e) + ' key = ' + key)
                    else:
                        log.debug('%s表创建唯一索引成功 索引为 %s' % (table, key))
            except:
                pass

    def close(self):
        with mysql_lock:
            self.conn.close()


if __name__ == '__main__':
    mc = MysqlDB()
    print(mc.find('select now()'))
